package com.raja.servingStation.common.util;

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.net.URLEncoder;
import java.util.*;

public class CSVUtils {
	

	/**
	 * 无时间类型导出（文件名自动生成）
	 * @param response
	 * @param fileName
	 * @param hearders
	 * @param fields
	 * @param dataList
	 */
	public static void exportCsvExtWithFile(HttpServletRequest request,
                                            HttpServletResponse response, String fileName, Object [] hearders,
											Object [] fields,
                                            List dataList) {
		
		String path = request.getServletPath();
		System.out.println("---------------------"+path+"--------------------------");
		
		String curTime = TimeUtil.dateToString(new Date());
		curTime = "_" + curTime.replaceAll("-", "").replaceAll(":", "").replaceAll(" ", "_");
		StringBuffer allFileName = new StringBuffer(fileName).append(curTime).append(".csv");
		
		Calendar cd = Calendar.getInstance();
		
		String fileDateName = String.valueOf(cd.get(Calendar.YEAR)) + String.valueOf(cd.get(Calendar.MONTH) + 1) 
				+ String.valueOf(cd.get(Calendar.DATE)) ;
		
		File file = new File(path+"\\download");
		
		if(!file.exists())file.mkdirs();
		
		StringBuffer filePath = new StringBuffer(path).append("\\").append(allFileName);
		
		boolean isSuccess = exportCsv(filePath.toString(), hearders, fields, dataList);
		
		if (isSuccess) {
			 export(response, filePath.toString(), allFileName.toString());
		}
		
	}


	/**
	 * 导出
	 * 
	 * @param fileName  csv文件(路径+文件名)，csv文件不存在会自动创建
	 * @param dataList 数据
	 * @return
	 */
	public static boolean exportCsv(String fileName, Object [] hearders, Object [] fields, List dataList) {
		boolean isSucess = false;

		FileOutputStream out = null;
		OutputStreamWriter osw = null;
		BufferedWriter bw = null;
		try {
			out = new FileOutputStream(new File(fileName));
			//增加GBK，防止windows office打开乱码
			osw = new OutputStreamWriter(out);
			bw = new BufferedWriter(osw);
			
			if (hearders != null && hearders.length > 0) {
				StringBuffer sb = new StringBuffer();
				for(int i=0;i<hearders.length;i++) {
					if (i == 0) {
						sb.append(hearders[i]);
					} else {
						sb.append(",").append(hearders[i]);
					}
				}
				bw.append(sb.toString()).append("\r");
			}
			if (dataList != null && !dataList.isEmpty()) {
				StringBuilder sb = new StringBuilder();
				for (Object obj : dataList){
					Map<String, Object> map = beanToMap(obj);
					if (fields != null && map != null) {
						sb.setLength(0);
						for(int i=0;i<fields.length;i++) {
							//String strTemp = (map.get(fields[i]) == null)?"":(String)map.get(fields[i]);
							if (i == 0) {
								//判断第一列是否是数字
								if (map.get(fields[i]) != null && map.get(fields[i]).toString().matches("[0-9]+")) {
									sb.append("'"+map.get(fields[i]));
								}else if(map.get(fields[i]) != null && !map.get(fields[i]).toString().matches("[0-9]+")) {
									sb.append(map.get(fields[i]));
								}else {
									sb.append("'");
								}
							} else {
								if (map.get(fields[i]) != null) {
									Object val = map.get(fields[i]);
									if(String.valueOf(map.get(fields[i])).indexOf('0') == 0
											&& !"0".equals(String.valueOf(map.get(fields[i])))
											&& String.valueOf(map.get(fields[i])).indexOf("0.") == 0){
										val = "'"+ val;
									}
									if(val.getClass() == String.class){
										val = ((String)val).replaceAll("\\n",";");
									}
									sb.append(",").append(val);
								} else {
									sb.append(",").append("");
								}
							}
						}
					}
					bw.append(sb.toString()).append("\r");
				}
			}
			isSucess = true;
		} catch (Exception e) {
			e.printStackTrace();
			isSucess = false;
		} finally {
			closeStream(out,osw,bw);
		}

		return isSucess;
	}
	
	/**
	 * JavaBean转Map
	 * @param obj
	 * @return
	 */
	public static Map<String, Object> beanToMap(Object obj) {  
        Map<String, Object> params = new HashMap<String, Object>(0);  
        try {  
            PropertyUtilsBean propertyUtilsBean = new PropertyUtilsBean();  
            PropertyDescriptor[] descriptors = propertyUtilsBean.getPropertyDescriptors(obj);  
            for (int i = 0; i < descriptors.length; i++) {  
                String name = descriptors[i].getName();  
                if (!StringUtils.equals(name, "class")) {
                    params.put(name, propertyUtilsBean.getNestedProperty(obj, name));  
                }  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
        return params;  
    }
	
	public static void export(HttpServletResponse response, String downloadfile, String fileName) {
		OutputStream o = null;
		FileInputStream in = null;
		File fileLoad = null;
		try {
			o = response.getOutputStream();
			byte b[] = new byte[500];
			fileLoad = new File(downloadfile);
	 
//			response.reset();


			CSVUtils.setFileDownloadHeader(response,fileName);
	
//			response.setContentType("application/csv");
			response.setContentType("application/octet-stream");
//			response.setHeader("ceshi","测试一下");
//			String newFilename= new String(fileName.getBytes(), "UTF-8");
//			String newFilename= new String(fileName.getBytes("GB2312"), "ISO_8859_1");
//			String newFilename= new String(fileName.getBytes("utf-8"), "ISO_8859_1");
			//String newFilename= java.net.URLEncoder.encode(fileName, "UTF-8");
//			response.setHeader("content-disposition", "attachment; filename=" + newFilename);
			long fileLength = fileLoad.length();
			String len = String.valueOf(fileLength);
			response.setHeader("Content_Length", len);
			response.setCharacterEncoding("GBK");
			in = new FileInputStream(fileLoad);
			int n;
			while ((n = in.read(b)) != -1) {
				o.write(b, 0, n);
			}
		} catch (IOException e) {
			e.printStackTrace();
		} finally {
			closeDownloadFile(o, in);
			if(fileLoad != null)
				fileLoad.delete();
		}
	}



	/**
	 * <pre>
	 * 浏览器下载文件时需要在服务端给出下载的文件名，当文件名是ASCII字符时没有问题
	 * 当文件名有非ASCII字符时就有可能出现乱码
	 *
	 * 这里的实现方式参考这篇文章
	 * http://blog.robotshell.org/2012/deal-with-http-header-encoding-for-file-download/
	 *
	 * 最终设置的response header是这样:
	 *
	 * Content-Disposition: attachment;
	 *                      filename="encoded_text";
	 *                      filename*=utf-8''encoded_text
	 *
	 * 其中encoded_text是经过RFC 3986的“百分号URL编码”规则处理过的文件名
	 * </pre>
	 * @param response
	 * @param filename
	 * @return
	 */
	public static void setFileDownloadHeader(HttpServletResponse response, String filename) {
		String headerValue = "attachment;";
		headerValue += " filename=" + encodeURIComponent(filename);
//		headerValue += " filename*=utf-8''" + encodeURIComponent(filename);
		response.setHeader("Content-Disposition", headerValue);
	}


	/**
	 * <pre>
	 * 符合 RFC 3986 标准的“百分号URL编码”
	 * 在这个方法里，空格会被编码成%20，而不是+
	 * 和浏览器的encodeURIComponent行为一致
	 * </pre>
	 * @param value
	 * @return
	 */
	public static String encodeURIComponent(String value) {
		try {
			return URLEncoder.encode(value, "UTF-8").replaceAll("\\+", "%20");
		} catch (UnsupportedEncodingException e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * 关闭下载的文件流
	 * @param o
	 * @param in
	 */
	private static void closeDownloadFile(OutputStream o, FileInputStream in) {
		if (in != null) {
            try {
                in.close();
                in = null;
            } catch (IOException e1) {
                e1.printStackTrace();
            }
        }
		if (o != null) {
            try {
                o.close();
                o = null;
            } catch (IOException e2) {
                e2.printStackTrace();
            }
        }
	}

	/**
	 * 关闭
	 * @param out
	 * @param osw
	 * @param bw
	 */
	private static void closeStream(FileOutputStream out, OutputStreamWriter osw, BufferedWriter bw) {
		try {
			if (bw != null) {
				bw.close();
				bw = null;
			}
			if (osw != null) {
				osw.close();
				osw = null;
			}
			if (out != null) {
				out.close();
				out = null;
			}
		}catch (Exception e){
			e.printStackTrace();
		}

	}
	
}
